package service

import (
	"errors"
	"gdmin/db"
	"gdmin/global"
	"gdmin/model"
	"gdmin/servlet"
	"gdmin/utils"
	"gorm.io/gorm"
)

type RoleService struct{}

func (s *RoleService) QueryRoleById(id string) *servlet.RoleResp {

	var role servlet.RoleResp
	global.DB.Where("id =?", id).First(&role)

	role.Menus = findMenus(role.Id)
	return &role
}

func findMenus(roleId int) []model.ResMenu {
	var menuIds []int
	global.DB.Model(&model.RoleBindMenu{}).Where("role_id = ?", roleId).Select("menu_id").Find(&menuIds)
	var res []model.ResMenu
	global.DB.Model(&model.ResMenu{}).Where("id in ?", menuIds).Find(&res)
	return res
}

func (s *RoleService) List() *[]servlet.RoleResp {
	var d []servlet.RoleResp
	global.DB.Model(&d).Find(&d)

	return &d
}

func (s *RoleService) QueryRole(req *servlet.QueryRoleReq) *servlet.Pagination {
	var d []*servlet.RoleResp
	query := global.DB.Model(&d)

	if req.Name != "" {
		query.Where("name like ? ", "%"+req.Name+"%")
	}

	if req.Code != "" {
		query.Where("code like? ", "%"+req.Code+"%")
	}

	page := db.CommonPage(&req.Pagination, &d, query)

	return page

}

func (s *RoleService) UpdateRole(req *servlet.UpdateRoleReq) (*model.Role, error) {

	if req.Id == 0 {
		return nil, errors.New("修改时id必填")

	}

	if req.Name == "" {
		return nil, errors.New("角色名称必填")
	}
	if req.Code == "" {
		return nil, errors.New("角色编码必填")
	}

	var old model.Role
	err := global.DB.First(&old, req.Id).Error
	if err != nil {
		return nil, err
	} else {

		err = checkRoleNameRequire(req.Name, req.Id)
		if err != nil {
			return nil, err
		}
		err = checkRoleCodeRequire(req.Code, req.Id)
		if err != nil {
			return nil, err
		}

		old.Name = req.Name
		old.Code = req.Code

		err = global.DB.Transaction(func(tx *gorm.DB) error {
			return tx.Save(&old).Error
		})
		if err != nil {
			return nil, err
		} else {

			return &old, nil

		}

	}

}

func checkRoleNameRequire(name string, id int) error {
	role := model.Role{}
	err := global.DB.Where("name =?", name).First(&role).Error
	if err == nil {
		if role.Id == 0 {
			return nil
		}
		if role.Id != id {
			return errors.New("角色名称已存在")
		}
	} else {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
	}

	return err
}

func checkRoleCodeRequire(code string, id int) error {
	role := model.Role{}
	err := global.DB.Where("code =?", code).First(&role).Error
	if err == nil {
		if role.Id == 0 {
			return nil
		}
		if role.Id != id {
			return errors.New("角色编码已存在")
		}
	} else {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
	}

	return err
}

func (*RoleService) CreateRole(req *servlet.CreateRoleReq) (*model.Role, error) {
	if req.Name == "" {
		return nil, errors.New("角色名称必填")
	}
	if req.Code == "" {
		return nil, errors.New("角色编码必填")
	}
	err := checkRoleNameRequire(req.Name, -1)
	if err != nil {
		return nil, err
	}
	err = checkRoleCodeRequire(req.Code, -1)
	if err != nil {
		return nil, err
	}

	if err != nil {
		return nil, err
	} else {
		var role model.Role
		role.Name = req.Name
		role.Code = req.Code

		err = global.DB.Transaction(func(tx *gorm.DB) error {
			return tx.Create(&role).Error
		})
		if err != nil {
			return nil, err
		} else {
			return &role, nil
		}
	}
}

func (s *RoleService) FindByUserIdWithName(userId int, resp *servlet.Userinfo) []string {
	roles := s.FindByUserId(userId)
	if roles == nil {
		return nil
	}
	var roleIds []int
	for _, role := range roles {
		roleIds = append(roleIds, role.Id)
	}

	resp.RoleIds = roleIds

	var roleNames []string
	for _, role := range roles {
		roleNames = append(roleNames, role.Name)
	}
	return roleNames
}
func (s *RoleService) FindByUserId(userId int) []model.Role {

	var roleIds []int
	global.DB.Model(&model.RoleBindUser{}).Where("user_id =?", userId).Select("role_id").Find(&roleIds)
	if len(roleIds) == 0 {
		return nil
	}
	var roles []model.Role
	global.DB.Model(&model.Role{}).Where("id in ?", roleIds).Find(&roles)
	return roles
}

func (s *RoleService) DeleteByIdRole(param string) {
	global.DB.Where("id =?", param).Delete(&model.Role{})
}

func (s *RoleService) RoleBindMenu(req *servlet.RoleBindMenu) error {
	return global.DB.Transaction(func(tx *gorm.DB) error {

		var dels []*model.RoleBindMenu
		tx.Model(&model.RoleBindMenu{}).Where("role_id = ?", req.RoleId).Find(&dels)
		for _, item := range dels {
			item.UpdateUserId = utils.GetThreadUserId()
			item.IsDel = 1
		}
		if len(dels) > 0 {

			err := tx.Save(&dels).Error
			if err != nil {
				return err
			}
		}
		for _, v := range req.MenuIds {
			var tosave model.RoleBindMenu
			tosave.MenuId = v
			tosave.RoleId = req.RoleId
			err := tx.Create(&tosave).Error
			if err != nil {
				return err
			}
		}
		return nil

	})

}
